module Foo

import std

struct tuple
{
	a : int
	b : string
}

// Automatically generated?
fun +tuple(+a, +b) // optional: -> tuple
{
	// Enforce order!
	this.a = ~a
	// Destruct on exception after initialization
	this.b = ~b
}
// Usage:
// -----
// def tuple = tuple(a, b)

// Placement function
fun +makeTuple(+a, +b) -> tuple
{
	// Delegating placement (BEFORE ANY OTHER CONSTRUCTION)
	this = tuple(~a, ~b)
}
// Usage:
// -----
// def tuple = makeTuple(a, b)

// Automatically generated?
fun +tuple(t : Tuple)
{
	this.a = t.a
	this.b = t.b
}

// Autoamtically generated?
fun +tuple(~t : tuple)
{
	this.a = ~t.a
	this.b = ~t.b
}

// Automatically generated
fun ~tuple()
{
	// this.b is destructed automatically
}

// Function with side effects
fun &print(message : string)
{
	// call global stuff
}

// Arithmetic TYPE concept
class Arithmetic
{
	fun operator +(Arithmetic, Arithmetic) -> Arithmetic
	fun operator -(Arithmetic, Arithmetic) -> Arithmetic
	fun operator *(Arithmetic, Arithmetic) -> Arithmetic
	fun operator /(Arithmetic, Arithmetic) -> Arithmetic
	fun operator %(Arithmetic, Arithmetic) -> Arithmetic
}

// Template function without side effects
fun foo(a : ?A : Arithmetic) -> A
{
	return a * 2
}
// Implicit metatype: <A : Arithmetic>(A) -> A

// Function with output parameters
fun insert(&tree, +element)
{
	// modify tree
}

fun trace(message)
{
	// evil
//	&i_know_what_i_m_doing_sucker { print(message) }
}

fun error(message) -> no_return // non-type keyword?
{
	trace(message)
	throw createError(message)
	
	// No-return any type inference hack?
	return error(message)
}

fun divide(a, b) = if (b != 0) a / b else error("Divide by zero")
// Implicit Metatype: <A, B>(A, B) -> typeof(A / B)

fun lambda_magic(container)
{
	for_each (container, fun(&a) { a *= 2})
	
	// Nice alternative
/*	for_each (container, fun(&a))
	{
		a *= 2
	}
*/	
	return container
}

fun fun_ret_fun() -> fun (int, float) -> string
{
	return some_fun // Return function
}

fun casting_and_rto()
{
	def a = 2.0f
	def b = a -> int
	
	def c = foo() -> int // Call "() -> int" overload
	def d = foo() -> float // Call "() -> float" overload
	
	def e = (foo() -> float) -> int // Call "() -> float" overload & cast
	
	def f = foo() -> fun (int, float) -> string // Call "() -> (int, float) -> string" overload
}

fun variables()
{
	def a = 2
	var b = 3
	
	a = 4 // error
	b = 6 // ok
}

typegroup Unsigned {}
// ...
typegroup Unsigned { uint }

// Pattern matching: Difficult to combine with overloading?
//fun fak(0 : Unsigned) = 1
//fun fak(a : Unsigned) = a * fak(a - 1)

struct unique_ptr => Value[]
{
	ptr : Value*
}

/* deprecated
fun get(ptr : *unique_ptr) -> value_type* = ptr:ptr
fun get(ptr : owned *unique_ptr) -> value_type *owned = ptr:ptr
*/

struct vector<Value, Traits>
{
	typedef value_type = Value
	typedef size_type = size_t
	typedef traits_type = Traits
	
	elements : unique_ptr => value_type[]
	// Evaluating funny alternatives
	size = 0 -> size_t;
}

// Teh star is gonna kill us: import symbols from vector :P
fun +fillVector(n : size_type, value : value_type) -> vector /* TODO: import using *vector? */
{
	this.elements = new value_type[n]
	fill_n(this.elements, n, value)
	this.size = n
}
// Implicit metatype: *<V, T>(vector<V, T>::size_type, vector<V, T>::value_type) -> vector<V, T>

typedef special_vector<Value> = vector => (Value, some_traits => Value)

fun guarded()
{
	var ptr = new Foo()
	guard (ptr) { delete ptr }
	
	// do sth. dangerous
	
	return unguard(ptr)
}

// TBC

// TODO:
// ----
// ptr mem access? (smart ptrs!)
// scope guards?
// const types?
// const reference types?
// non-null-ptrs?
// constexpr?
// exceptions?
// operator overloading?
// type groups? (type : ...)
// namespaces!
